package com.a0soft.gphone.aTruffleHog.util;
/*
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 3, or (at your option) any
 * later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * Copyright(C) 2011 
 *   Sam Lu <ysl.sam.lu (at) gmail.com>
 *
 */

import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.security.MessageDigest;

import com.a0soft.gphone.aTruffleHog.srvc.HttpConnSrvc;

import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.hardware.SensorManager;
import android.util.DisplayMetrics;

public class MiscUtil {
    private static Context  m_ctx;
    private static SensorManager m_sm; //cache here as it cannot be get from a non-ui thread
    
	private static Method	m_readProcLines;
	private static boolean	m_bReadProcLinesInit;
	
    private static float m_fDensity = Float.NaN;
    private static float m_fScaledDensity = Float.NaN;
	
	private static final String LOG_TAG = MiscUtil.class.getSimpleName();
	
	public static void
	Init(Context ctx)
	{
	    m_ctx = ctx.getApplicationContext();
	    m_sm = (SensorManager)ctx.getSystemService(Context.SENSOR_SERVICE); 
	    
	    //check if HttpConnSrvc is declared in AndroidManifest.xml
	    boolean bServiceDeclared = false;
	    ComponentName cn = new ComponentName(ctx, HttpConnSrvc.class);
	    PackageManager pm = ctx.getPackageManager();
	    try {
            pm.getServiceInfo(cn, 0);
            int nEnabled = pm.getComponentEnabledSetting(cn);
            if (aDebug.ENABLED) {
                aDebug.d(LOG_TAG, cn.getClassName() + " enabled=" + nEnabled);
            }
            if (nEnabled != PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
                bServiceDeclared = true;
            }
        }
        catch (NameNotFoundException e) {
            if (aDebug.ENABLED) {
                aDebug.d(LOG_TAG, cn.getClassName() + " not declared!");
            }
        }
	    if (!bServiceDeclared) {
	        throw new IllegalArgumentException("Please declare and enable " + cn.getClassName() + " in your AndroidManifest.xml!");
	    }
	    
	    if (aDebug.ENABLED) {
            aDebug.d(LOG_TAG, "target sdk version=" + ctx.getApplicationInfo().targetSdkVersion);
        }
	}
	
	public static Context
	GetAppContext()
	{
	    return m_ctx;
	}
	
	public static SensorManager
    GetSensorManager()
	{
	    return m_sm;
	}
	
	public static int
	GetSDKVersion()
	{
		return android.os.Build.VERSION.SDK_INT;
	}
	
	public static final long
	ReadProcOuput(String strPath, StringBuilder sb)
	{
		ProcessBuilder pb;
		InputStreamReader isr = null;
		long lSize = 0;
		
		try {
			String[] args = {"/system/bin/cat", strPath};
			pb = new ProcessBuilder(args);
			
			//pb(true);
			Process process = pb.start();
			
			try { process.getOutputStream().close(); } catch (IOException e) {}
            //try { process.getErrorStream().close(); } catch (IOException e) {}
            
			isr = new InputStreamReader(process.getInputStream());
			int nNum;
            char[] buf = new char[8192];
            while ((nNum = isr.read(buf)) > 0) {
            	sb.append(buf, 0, nNum);
            	lSize += nNum;
            }
		}
		catch (IOException e) {
			if (aDebug.ENABLED)
				aDebug.e(LOG_TAG, "ReadProcOuput()", e);
		}
		finally {
          if (isr != null) 
        	  try { 
        		  isr.close(); 
        	  } catch (IOException e) {}
		}
		return lSize;
	}
	
	public static final void 
	ReadProcLines(String path, String[] reqFields, long[] outSizes)
	{
		if (!m_bReadProcLinesInit) {
			try {
				m_readProcLines = android.os.Process.class.getMethod("readProcLines", String.class, String[].class, long[].class);
				m_readProcLines.setAccessible(true);
			} catch (Exception e) {
				if (aDebug.ENABLED)
					aDebug.e(LOG_TAG, "no readProcLines()", e);
            }
		}
		
		if (m_readProcLines == null)
			return;
		
		try {
			m_readProcLines.invoke(null, path, reqFields, outSizes);
		} catch (Exception e) {
        	if (aDebug.ENABLED)
				aDebug.e(LOG_TAG, "ReadProcLines()", e);
        }
	}
	
	public static int 
    GetClassIntField(Class<?> cls, Object obj, String strFieldName) 
    {
        try {
            Field field = cls.getField(strFieldName);
            return (Integer)field.get(obj);
        } catch (Exception e) {
        }
      	return Integer.MIN_VALUE;
    }
	
	public static String 
    GetClassStringField(Class<?> cls, Object obj, String strFieldName) 
    {
        try {
            Field field = cls.getField(strFieldName);
            return (String)field.get(obj);
        } catch (Exception e) {
        }
     	return null;
    }
	
	public static String 
    MD5(String val)
    {
        String result = null;
        
        if (val != null && val.length() > 0) {
            try {
                MessageDigest md5 = MessageDigest.getInstance("MD5");
                result = String.format("%032X", new BigInteger(1, md5.digest(val.getBytes())));
            }
            catch (Exception e) {
                if (aDebug.ENABLED)
                    aDebug.e(LOG_TAG, "Could not generate hash of " + val, e);
                result = String.format("%032X", val.hashCode());
            }
        }
        
        return result;
    }
	
	private static void
	_CheckInitDisplayMetrics()
	{
	    if (Float.isNaN(m_fDensity)) {
	        Context ctx = m_ctx;
	        final DisplayMetrics dm = ctx.getResources().getDisplayMetrics();
	        m_fDensity = dm.density;
	        m_fScaledDensity = dm.scaledDensity;
	    }
	}
	
	public static float
    GetPixelFromDP(float fDP)
    {
        _CheckInitDisplayMetrics();
        
        if (m_fDensity == 1.0f) return fDP;
        return fDP * m_fDensity;
    }
	
	public final float
    GetDPFromPixel(float fPixel)
    {
        _CheckInitDisplayMetrics();
        
        if (m_fDensity == 1.0f) return fPixel;
        return fPixel / m_fDensity;
    }
	
	public static float
    GetPixelFromSP(float fSP)
    {
        _CheckInitDisplayMetrics();
        
        if (m_fScaledDensity == 1.0f) return fSP;
        return fSP * m_fScaledDensity;
    }
    
    public final float
    GetSPFromPixel(float fPixel)
    {
        _CheckInitDisplayMetrics();
        
        if (m_fScaledDensity == 1.0f) return fPixel;
        return fPixel / m_fScaledDensity;
    }
}
